package com.ydlclass.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ydlclass.configuration.CustomObjectMapper;
import com.ydlclass.configuration.RedisTemplate;
import com.ydlclass.constants.Constants;
import com.ydlclass.dao.YdlUserDao;
import com.ydlclass.entity.YdlLoginUser;
import com.ydlclass.entity.YdlUser;
import com.ydlclass.exception.UserNotFoundException;
import com.ydlclass.exception.passwordNotFoundException;
import com.ydlclass.service.YdlUserService;
import eu.bitwalker.useragentutils.UserAgent;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * 用户信息表(YdlUser)表服务实现类
 *
 * @author makejava
 * @since 2022-09-17 16:59:08
 */
@Service("ydlUserService")
public class YdlUserServiceImpl implements YdlUserService {
    @Resource
    private YdlUserDao ydlUserDao;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    private CustomObjectMapper objectMapper;
    @Resource
    private RedisTemplate redisTemplate;

    //判断登录用户
    @Override
    public YdlLoginUser login(String userName, String password) throws UserNotFoundException, JsonProcessingException, passwordNotFoundException {
        //1.验证前端的用户名和密码是否正确
        YdlUser ydlUser = ydlUserDao.queryByUserName(userName);
        if (Objects.isNull(ydlUser)) throw new UserNotFoundException("用户名不存在");
        if (!ydlUser.getPassword().equals(password)) throw new passwordNotFoundException("密码不正确");
        //2.生成token
        String token = UUID.randomUUID().toString();
        //3.在servlet请求中获取所需信息
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        UserAgent userAgent = new UserAgent(request.getHeader("User-Agent"));
        // 通过ip获取其所属的地址:广东省xxx
        ResponseEntity<String> result = restTemplate.getForEntity("https://whois.pconline.com.cn/ipJson.jsp?ip=" + request.getRemoteHost() + "&json=true", String.class);
        String body = result.getBody();
        Map<String, String> map = objectMapper.readValue(body, new TypeReference<Map>() {
        });
        String location = map.get("addr") + map.get("pro") + map.get("city") + map.get("region");
        //  封装一个YdlLoginUser，保存在redis
        YdlLoginUser ydlLoginUser = YdlLoginUser.builder()
                .userId(ydlUser.getUserId())
                .token(token)
                .ipaddr(request.getRemoteAddr())
                .loginTime(new Date())
                .os(userAgent.getOperatingSystem().getName())
                .browser(userAgent.getBrowser().getName())
                .loginLocation(location)
                .ydlUser(ydlUser)
                .build();
        //key进行处理  token:username:uuid

        // 1、根据用户名生成一个key前缀token:username:
        String keyPrefix = Constants.TOKEN_PREFIX ;

        // 4、把新的数据加入redis
        redisTemplate.setObject(keyPrefix + token, ydlLoginUser, Constants.TOKEN_TIME);
        //更新登录ip和时间
        ydlUser.setLoginDate(new Date());
        ydlUser.setLoginIp(request.getRemoteHost());
        ydlUserDao.update(ydlUser);
        return ydlLoginUser;
    }

    @Override
    public YdlUser queryByUserName(String userName) {
        return ydlUserDao.queryByUserName(userName);
    }


    // 获取当前登陆用户的方法
    private YdlLoginUser getLoginUser() {

        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        // 获取首部信息的token
        String token = request.getHeader(Constants.HEAD_AUTHORIZATION);
        System.out.println("token---"+token.toString());

        if (token == null) {
            throw new RuntimeException("当前用户未登录！");
        }
        Set<String> keys = redisTemplate.keys(Constants.TOKEN_PREFIX + "*" + token);
        if (keys == null || keys.size() == 0) {
            throw new RuntimeException("当前用户未登录！");
        }
        String tokenKey = (String) keys.toArray()[0];
        // 3、使用token去redis中查看，有没有对应的loginUser

        YdlLoginUser loginUser = redisTemplate.getObject(tokenKey, new TypeReference<YdlLoginUser>() {});
        return loginUser;
    }

    @Override
    public HashMap<String, Object> getInfo() {
        // 1、获取当前登陆的对象
        System.out.println("进入getInfo1--Service");
        YdlLoginUser loginUser = getLoginUser();
        System.out.println("进入getInfo2--Service");
//        查到的字段不是ydluser
        // 2、查询当前用户的角色和权限
        List<Map<String, Object>> ListInfo = ydlUserDao.getInfo(loginUser.getUserId());
        List roleTagList=new ArrayList();
        List permsList=new ArrayList();
        ListInfo.forEach(map -> roleTagList.add(map.get("role_tag")));
        ListInfo.forEach(map -> permsList.add(map.get("perms")));
        redisTemplate.setObject(Constants.ROLE_PREFIX + loginUser.getToken(),roleTagList, Constants.TOKEN_TIME);
        redisTemplate.setObject(Constants.PERM_PREFIX + loginUser.getToken(), permsList, Constants.TOKEN_TIME);
        HashMap<String, Object> hashMap = new HashMap<String, Object>();
        hashMap.put("role_tag",roleTagList);
        hashMap.put("perms",permsList);
        return hashMap;


        // 3、处理权限和角色的相关信息
        // (1) roles:token : [admin,xxx,yyy]   perms:token: [system:user:add,system:user:update]



        // [{roleName:cc,roleTag:xxx,perms:[{id,'xxx',perm:'system'},{id,'xxx',perm:'system'}]},{}]
        // [[{id,'xxx',perm:'system'},{id,'xxx',perm:'system'}],[{id,'xxx',perm:'system'},{id,'xxx',perm:'system'}]]
        // ['system','system:user:add']
        //YdlUser里面有YdlRoles里面有YdlMenus里面有perms,抽出成list集合
        // 整合数据
    }

    /**
     * 通过ID查询单条数据
     *
     * @param userId 主键
     * @return 实例对象
     */
    @Override
    public YdlUser queryById(Long userId) {
        return this.ydlUserDao.queryById(userId);
    }

    /**
     * 分页查询
     *
     * @param ydlUser     筛选条件
     * @param pageRequest 分页对象
     * @return 查询结果
     */
    @Override
    public Page<YdlUser> queryByPage(YdlUser ydlUser, PageRequest pageRequest) {
        long total = this.ydlUserDao.count(ydlUser);
        return new PageImpl<>(this.ydlUserDao.queryAllByLimit(ydlUser, pageRequest), pageRequest, total);
    }

    //模糊查询所有
    @Override
    public List<YdlUser> queryLike(String userName, String nickName) {
        return this.ydlUserDao.queryLike(userName, nickName);
    }


    @Override
    public PageInfo<YdlUser> findUserByPage(YdlUser ydlUser, int pageNum, int pageSize) {
        //传入当前页码和每页显示数据的条数
        if (pageNum == 0)
            pageNum = 1;//当到最后一页时，其下一页的Pagenum的值为0  所有要给Pagenum赋值
        //使用分页插件工具完成分页
        PageHelper.startPage(pageNum, pageSize);
        //查询所有的用户数据
        List<YdlUser> list = this.ydlUserDao.queryLike(ydlUser.getUserName(), ydlUser.getNickName());
        //将所有用户数据传入PageInfo<User>中，其他的属性会根据当前页的数据计算出来
        PageInfo pageInfo = new PageInfo(list);
        return pageInfo;

    }


    /**
     * 新增数据
     *
     * @param ydlUser 实例对象
     * @return 实例对象
     */
    @Override
    public YdlUser insert(YdlUser ydlUser) {
        this.ydlUserDao.insert(ydlUser);
        return ydlUser;
    }

    /**
     * 修改数据
     *
     * @param ydlUser 实例对象
     * @return 实例对象
     */
    @Override
    public YdlUser update(YdlUser ydlUser) {
        this.ydlUserDao.update(ydlUser);
        return this.queryById(ydlUser.getUserId());
    }

    /**
     * 通过主键删除数据
     *
     * @param userId 主键
     * @return 是否成功
     */
    @Override
    public boolean deleteById(Long userId) {
        return this.ydlUserDao.deleteById(userId) > 0;
    }
}
